#include "Dispatcher.h"
#include <stdio.h>
#include <sys/select.h>
#include <stdlib.h>

#define MAX 1024
struct SelectData
{
    fd_set readSet;
    fd_set writeSet;
};

//init--初始化
static void* selectInit();
//add
static int selectAdd(struct Channel* Channel, struct EventLoop* eventLoop);
//del
static int selectRemove(struct Channel* Channel, struct EventLoop* eventLoop);
//修改
static int selectModify(struct Channel* Channel, struct EventLoop* eventLoop);
//事件监测
static int selectDispatch(struct EventLoop* eventLoop, int timeout);//单位:s
//清除数据(关闭fd或者释放内存)
static int selectClear(struct EventLoop* eventLoop);
static void setFdSet(struct Channel* Channel, struct SelectData* data);
static void clearFdSet(struct Channel* Channel, struct SelectData* data);

//全局变量
struct Dispatcher SelectDispatcher = {
    selectInit,
    selectAdd,
    selectRemove,
    selectModify,
    selectDispatch,
    selectClear
};

//init--初始化
static void* selectInit()
{
    struct SelectData* data = (struct SelectData*)malloc(sizeof(struct SelectData));
    FD_ZERO(&data->readSet);//清空集合
    FD_ZERO(&data->writeSet);
    return data;
}

static void setFdSet(struct Channel* Channel, struct SelectData* data)
{
    if(Channel->events & ReadEvent)//放读集合
    {
        FD_SET(Channel->fd, &data->readSet);
    }
    //这里不能用else，因为读写事件可以同时存在
    if(Channel->events & WriteEvent)//放写集合
    {
        FD_SET(Channel->fd, &data->writeSet);
    }
}

static void clearFdSet(struct Channel* Channel, struct SelectData* data)
{
    if(Channel->events & ReadEvent)
    {
        FD_CLR(Channel->fd, &data->readSet);
    }
    //这里不能用else，因为读写事件可以同时存在
    if(Channel->events & WriteEvent)
    {
        FD_CLR(Channel->fd, &data->writeSet);
    }
}

//add
static int selectAdd(struct Channel* Channel, struct EventLoop* eventLoop)
{
    struct SelectData* data = (struct SelectData*)eventLoop->dispatcherData;
    if(Channel->fd >= MAX)
    {
        return -1;
    }
    setFdSet(Channel, data);
    return 0;
}

//del
static int selectRemove(struct Channel* Channel, struct EventLoop* eventLoop)
{
    struct SelectData* data = (struct SelectData*)eventLoop->dispatcherData;
    clearFdSet(Channel, data);
    //通过channel释放对应的TcpConnection资源
    Channel->destroyCallBack(Channel->arg);
    return 0;
}

//修改
static int selectModify(struct Channel* Channel, struct EventLoop* eventLoop)
{
    struct SelectData* data = (struct SelectData*)eventLoop->dispatcherData;
    clearFdSet(Channel, data);
    setFdSet(Channel, data);
    return 0;
}

//事件监测
static int selectDispatch(struct EventLoop* eventLoop, int timeout)//单位:s
{
    struct SelectData* data = (struct SelectData*)eventLoop->dispatcherData;
    struct timeval val;
    val.tv_sec = timeout;//秒
    val.tv_usec = 0;//微秒
    //把data里的读写集合传进去会被修改，所以要用临时的变量去传
    fd_set rdtmp = data->readSet;
    fd_set wrtmp = data->writeSet;
    int count = select(MAX, &rdtmp, &wrtmp, NULL, &val);//S转为MS
    if(count == -1)
    {
        perror("select");
        exit(0);
    }
    for(int idx = 0; idx < MAX; idx++)
    {
        //这里文件描述符与下标一致
        if(FD_ISSET(idx, &rdtmp))//该文件描述符在读集合中
        {
            eventActivate(eventLoop, idx, ReadEvent);
        }
        
        if(FD_ISSET(idx, &wrtmp))//该文件描述符在写集合中
        {
            eventActivate(eventLoop, idx, WriteEvent);
        }
    }
    return 0;
}

//清除数据(关闭fd或者释放内存)
static int selectClear(struct EventLoop* eventLoop)
{
    struct SelectData* data = (struct SelectData*)eventLoop->dispatcherData;
    free(data);
    eventLoop->dispatcherData = NULL;
    return 0;
}

